﻿using System.Security.Cryptography;
using Admin.ApplicationLib.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Swimj.Core.Securities;

namespace Admin.ApplicationLib
{
    public class AdminApplicationDbContextSeed
    {
        private readonly IPasswordHasher<UserEntity> _passwordHasher = new PasswordHasher<UserEntity>();
        private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        private AdminApplicationDbContext _dbContext;
#if NET6_0_OR_GREATER
        public static string GenerateBase32()
        {
            const int length = 20;
            // base32 takes 5 bytes and converts them into 8 characters, which would be (byte length / 5) * 8
            // except that it also pads ('=') for the last processed chunk if it's less than 5 bytes.
            // So in order to handle the padding we add 1 less than the chunk size to our byte length
            // which will either be removed due to integer division truncation if the length was already a multiple of 5
            // or it will increase the divided length by 1 meaning that a 1-4 byte length chunk will be 1 instead of 0
            // so the padding is now included in our string length calculation
            return string.Create(((length + 4) / 5) * 8, 0, static (buffer, _) =>
            {
                Span<byte> bytes = stackalloc byte[length];
                RandomNumberGenerator.Fill(bytes);

                var index = 0;
                for (int offset = 0; offset < bytes.Length;)
                {
                    byte a, b, c, d, e, f, g, h;
                    int numCharsToOutput = GetNextGroup(bytes, ref offset, out a, out b, out c, out d, out e, out f,
                        out g,
                        out h);

                    buffer[index + 7] = ((numCharsToOutput >= 8) ? Base32Chars[h] : '=');
                    buffer[index + 6] = ((numCharsToOutput >= 7) ? Base32Chars[g] : '=');
                    buffer[index + 5] = ((numCharsToOutput >= 6) ? Base32Chars[f] : '=');
                    buffer[index + 4] = ((numCharsToOutput >= 5) ? Base32Chars[e] : '=');
                    buffer[index + 3] = ((numCharsToOutput >= 4) ? Base32Chars[d] : '=');
                    buffer[index + 2] = (numCharsToOutput >= 3) ? Base32Chars[c] : '=';
                    buffer[index + 1] = (numCharsToOutput >= 2) ? Base32Chars[b] : '=';
                    buffer[index] = (numCharsToOutput >= 1) ? Base32Chars[a] : '=';
                    index += 8;
                }
            });
        }
#endif

        private static int GetNextGroup(Span<byte> input, ref int offset, out byte a, out byte b, out byte c,
            out byte d,
            out byte e, out byte f, out byte g, out byte h)
        {
            uint b1, b2, b3, b4, b5;

            int retVal;
            switch (input.Length - offset)
            {
                case 1:
                    retVal = 2;
                    break;
                case 2:
                    retVal = 4;
                    break;
                case 3:
                    retVal = 5;
                    break;
                case 4:
                    retVal = 7;
                    break;
                default:
                    retVal = 8;
                    break;
            }

            b1 = (offset < input.Length) ? input[offset++] : 0U;
            b2 = (offset < input.Length) ? input[offset++] : 0U;
            b3 = (offset < input.Length) ? input[offset++] : 0U;
            b4 = (offset < input.Length) ? input[offset++] : 0U;
            b5 = (offset < input.Length) ? input[offset++] : 0U;

            a = (byte)(b1 >> 3);
            b = (byte)(((b1 & 0x07) << 2) | (b2 >> 6));
            c = (byte)((b2 >> 1) & 0x1f);
            d = (byte)(((b2 & 0x01) << 4) | (b3 >> 4));
            e = (byte)(((b3 & 0x0f) << 1) | (b4 >> 7));
            f = (byte)((b4 >> 2) & 0x1f);
            g = (byte)(((b4 & 0x3) << 3) | (b5 >> 5));
            h = (byte)(b5 & 0x1f);

            return retVal;
        }

        public async Task SeedAsync(AdminApplicationDbContext context, ILogger<AdminApplicationDbContextSeed> logger,
            int? retry = 0)
        {
            _dbContext = context;
            if (retry != null)
            {
                var retryForAvaiability = retry.Value;

                try
                {
                    //var useCustomizationData = settings.Value.UseCustomizationData;
                    //var contentRootPath = env.ContentRootPath;

                    var addInMemoryUser = GetDefaultUsers();
                    var user = context.Users.FirstOrDefault(i => i.UserName.Equals(addInMemoryUser.UserName));

                    if (user == null)
                    {
                        context.Users.Add(addInMemoryUser);

                        await context.SaveChangesAsync();
                    }

                    var addInMemoryRole = GetDefaultRoles();
                    var role = context.Roles.FirstOrDefault(i => i.Code.Equals(addInMemoryRole.Code));

                    if (role == null)
                    {
                        context.Roles.Add(addInMemoryRole);

                        await context.SaveChangesAsync();
                    }

                    Guid userId;
                    Guid roleId;

                    if (user == null || role == null)
                    {
                        if (user == null)
                        {
                            userId = addInMemoryUser.Id;
                        }
                        else
                        {
                            userId = user.Id;
                        }

                        if (role == null)
                        {
                            roleId = addInMemoryRole.Id;
                        }
                        else
                        {
                            roleId = role.Id;
                        }
                    }
                    else
                    {
                        userId = user.Id;
                        roleId = role.Id;
                    }

                    var userRoleEntity =
                        context.UserRoles.FirstOrDefault(i => i.UserId == userId && i.RoleId == roleId);
                    if (userRoleEntity == null)
                    {
                        context.UserRoles.Add(new UserRoleEntity()
                        {
                            UserId = userId,
                            RoleId = roleId
                        });
                        await context.SaveChangesAsync();
                    }

                    var addInMemoryPermissions = GetDefaultPermissions();
                    var addInMemoryPermissionNames = addInMemoryPermissions.Select(i => i.Code).ToList();
                    var hasPermissions = context.Permissions?.Where(i => addInMemoryPermissionNames.Contains(i.Code))
                        .ToList();

                    var addPermissions = addInMemoryPermissions.Where(i =>
                            hasPermissions != null && !hasPermissions.Any(m => m.Code != null && m.Code.Equals(i.Code)))
                        .ToList();

                    if (addPermissions.Any())
                    {
                        // context.Permissions?.AddRange(addPermissions);

                        foreach (var permissionEntity in addPermissions)
                        {
                            context.Permissions?.Add(permissionEntity);

                            context.RoleClaims.Add(new RoleClaimEntity()
                            {
                                RoleId = roleId,
                                ClaimType = "Permission",
                                ClaimValue = permissionEntity.Code
                            });
                        }

                        await context.SaveChangesAsync();
                    }
                }
                catch (Exception ex)
                {
                    if (retryForAvaiability < 10)
                    {
                        retryForAvaiability++;

                        logger.LogError(ex, "EXCEPTION ERROR while migrating {DbContextName}",
                            nameof(AdminApplicationDbContext));

                        await SeedAsync(context, logger, retryForAvaiability);
                    }
                }
            }
        }

        // 设置初始化用户
        private UserEntity GetDefaultUsers()
        {
            var user = new UserEntity()
            {
                Id = _dbContext.SecurityUser.GetUserId()!.Value,
                UserName = "admin",
                NormalizedUserName = "ADMIN",
                RealName = "admin",
                PhoneNumber = "88888888",
                Email = "admin@microsoft.com",
                NormalizedEmail = "ADMIN@MICROSOFT.COM",
                SecurityStamp = GenerateBase32(),
                DataState = 1
            };

            user.PasswordHash = _passwordHasher.HashPassword(user, "1q2w3E!");

            return user;
        }

        // 设置初始化角色
        private RoleEntity GetDefaultRoles()
        {
            var role = new RoleEntity()
            {
                Code = "admin",
                Name = "系统管理员"
            };

            return role;
        }

        // 设置初始化菜单
        public IList<PermissionEntity> GetDefaultPermissions()
        {
            var dashboard = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "Dashboard",
                Name = "Dashboard",
                Type = "URL",
                Icon = "mdi mdi-home-outline",
                Uri = "/home/index",
                Sort = 1,
                Level = 0
            };

            var auth = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "AuthManage",
                Name = "权限设置",
                Type = "MENU",
                Icon = "mdi mdi-account-supervisor-outline",
                Sort = 2,
                Level = 0
            };

            var user = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "UserManage",
                Name = "用户管理",
                Type = "URL",
                ParentId = auth.Id,
                Uri = "/users/index",
                Sort = 200,
                Level = 1
            };

            var queryUsers = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "QueryUsers",
                Name = "查询",
                Type = "Action",
                Uri = "QueryUsers",
                Sort = 200001,
                Level = 2
            };

            var createUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "CreateUser",
                Name = "新增",
                Type = "Action",
                Uri = "CreateUser",
                Sort = 200002,
                Level = 2
            };

            var updateUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "UpdateUser",
                Name = "修改",
                Type = "Action",
                Uri = "UpdateUser",
                Sort = 200003,
                Level = 2
            };

            var deleteUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "DeleteUser",
                Name = "删除",
                Type = "Action",
                Uri = "DeleteUser",
                Sort = 200004,
                Level = 2
            };

            var exportUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "ExportUser",
                Name = "导出",
                Type = "Action",
                Uri = "ExportUser",
                Sort = 200005,
                Level = 2
            };

            var importUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "ImportUser",
                Name = "导入",
                Type = "Action",
                Uri = "ImportUser",
                Sort = 200006,
                Level = 2
            };

            var getUser = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = user.Id,
                Code = "GetUser",
                Name = "明细",
                Type = "Action",
                Uri = "GetUser",
                Sort = 200007,
                Level = 2
            };

            var role = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "RoleManage",
                Name = "角色管理",
                Type = "URL",
                ParentId = auth.Id,
                Uri = "/roles/index",
                Sort = 201,
                Level = 1
            };


            var queryRoles = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "QueryRoles",
                Name = "查询",
                Type = "Action",
                Uri = "QueryRoles",
                Sort = 201001,
                Level = 2
            };

            var createRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "CreateRole",
                Name = "新增",
                Type = "Action",
                Uri = "CreateRole",
                Sort = 201002,
                Level = 2
            };

            var updateRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "UpdateRole",
                Name = "修改",
                Type = "Action",
                Uri = "UpdateRole",
                Sort = 201003,
                Level = 2
            };

            var deleteRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "DeleteRole",
                Name = "删除",
                Type = "Action",
                Uri = "DeleteRole",
                Sort = 201004,
                Level = 2
            };

            var exportRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "ExportRole",
                Name = "导出",
                Type = "Action",
                Uri = "ExportRole",
                Sort = 201005,
                Level = 2
            };

            var importRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "ImportRole",
                Name = "导入",
                Type = "Action",
                Uri = "ImportRole",
                Sort = 201006,
                Level = 2
            };

            var getRole = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = role.Id,
                Code = "GetRole",
                Name = "明细",
                Type = "Action",
                Uri = "GetRole",
                Sort = 201007,
                Level = 2
            };

            var permission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "PermissionManage",
                Name = "权限管理",
                Type = "URL",
                ParentId = auth.Id,
                Uri = "/permissions/index",
                Sort = 202,
                Level = 1
            };


            var queryPermissions = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "QueryPermissions",
                Name = "查询",
                Type = "Action",
                Uri = "QueryPermissions",
                Sort = 202001,
                Level = 2
            };

            var createPermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "CreatePermission",
                Name = "新增",
                Type = "Action",
                Uri = "CreatePermission",
                Sort = 202002,
                Level = 2
            };

            var updatePermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "UpdatePermission",
                Name = "修改",
                Type = "Action",
                Uri = "UpdatePermission",
                Sort = 202003,
                Level = 2
            };

            var deletePermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "DeletePermission",
                Name = "删除",
                Type = "Action",
                Uri = "DeletePermission",
                Sort = 202004,
                Level = 2
            };

            var exportPermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "ExportPermission",
                Name = "导出",
                Type = "Action",
                Uri = "ExportPermission",
                Sort = 202005,
                Level = 2
            };

            var importPermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "ImportPermission",
                Name = "导入",
                Type = "Action",
                Uri = "ImportPermission",
                Sort = 202006,
                Level = 2
            };

            var getPermission = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                ParentId = permission.Id,
                Code = "GetPermission",
                Name = "明细",
                Type = "Action",
                Uri = "GetPermission",
                Sort = 202007,
                Level = 2
            };

            var roleEmpower = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "RoleEmpowerManage",
                Name = "角色授权",
                Type = "URL",
                ParentId = auth.Id,
                Uri = "/security/index",
                Sort = 203,
                Level = 1
            };

            var workflow = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "WorkflowManage",
                Name = "流程管理",
                Type = "Menu",
                Icon = "mdi mdi-sitemap-outline",
                Sort = 3,
                Level = 0
            };

            var dataServer = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "DataServerManage",
                Name = "数据服务",
                Type = "MENU",
                Icon = "mdi mdi-database-outline",
                Sort = 4,
                Level = 0
            };

            var system = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "SystemManage",
                Name = "系统管理",
                Type = "MENU",
                Icon = "mdi mdi-cog-outline",
                Sort = 5,
                Level = 0
            };

            var device = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "DeviceManage",
                Name = "设备管理",
                Type = "Menu",
                Icon = "mdi mdi-devices",
                Sort = 6,
                Level = 0
            };

            var production = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "ProductionManage",
                Name = "生产管理",
                Type = "Menu",
                Icon = "mdi mdi-calculator",
                Sort = 7,
                Level = 0
            };

            var baseData = new PermissionEntity()
            {
                Id = Guid.NewGuid(),
                Code = "BaseDataManage",
                Name = "基础数据",
                Type = "Menu",
                Icon = "mdi mdi-table-cog",
                Sort = 8,
                Level = 0
            };

            // var permissionEntities = new List<PermissionEntity>()
            // {
            //     
            //     new()
            //     {
            //         Code = "DatabaseManage",
            //         Name = "数据库管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/database",
            //         Sort = 300
            //     },
            //     new()
            //     {
            //         Code = "DataSourceManage",
            //         Name = "数据源管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/dataSource",
            //         Sort = 301
            //     },
            //     new()
            //     {
            //         Code = "DimensionManage",
            //         Name = "维度管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/dimension",
            //         Sort = 302
            //     },
            //     new()
            //     {
            //         Code = "InterfaceManage",
            //         Name = "接口管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/interface",
            //         Sort = 303
            //     },
            //     new()
            //     {
            //         Code = "ReportManage",
            //         Name = "报表管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/report",
            //         Sort = 304
            //     },
            //     new()
            //     {
            //         Code = "DataConfigManage",
            //         Name = "配置管理",
            //         Type = "URL",
            //         ParentId = dataServer.Id,
            //         Uri = "/dataServer/dataConfig",
            //         Sort = 305
            //     }
            // };


            return new List<PermissionEntity>
            {
                dashboard,
                auth,
                user,
                queryUsers,
                createUser,
                updateUser,
                deleteUser,
                exportUser,
                importUser,
                getUser,
                role,
                queryRoles,
                createRole,
                updateRole,
                deleteRole,
                exportRole,
                importRole,
                getRole,
                permission,
                queryPermissions,
                createPermission,
                updatePermission,
                deletePermission,
                exportPermission,
                importPermission,
                getPermission,
                roleEmpower
            };
        }
    }
}